package org.xc.uvc_camera;

import android.content.DialogInterface;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Surface;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.jiangdg.usbcamera.UVCCameraHelper;
import com.jiangdg.usbcamera.utils.FileUtils;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.core.breakpoint.BlockInfo;
import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.listener.DownloadListener4;
import com.liulishuo.okdownload.core.listener.assist.Listener4Assist;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.Size;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usb.common.AbstractUVCCameraHandler;
import com.serenegiant.usb.widget.CameraViewInterface;

import org.xc.uvc_camera.net.AppVersion;
import org.xc.uvc_camera.net.Req;
import org.xc.uvc_camera.net.api.Other;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;

/**
 * UVCCamera use demo
 * <p>
 * Created by jiangdongguo on 2017/9/30.
 */

public class USBCameraActivity extends AppCompatActivity implements CameraDialog.CameraDialogParent, CameraViewInterface.Callback {
    private static final String TAG = "Debug";
    public View mTextureView;

    private ProgressBar pb;
    private Button btn_upload;

    private FrameLayout fl_down;

    private UVCCameraHelper mCameraHelper;
    private CameraViewInterface mUVCCameraView;

    private boolean isRequest;
    private boolean isPreview;

    private Disposable recordDisposable;
    private Disposable countDisposable;
    private Disposable onlineDisposable;

    private UVCCameraHelper.OnMyDevConnectListener listener = new UVCCameraHelper.OnMyDevConnectListener() {

        @Override
        public void onAttachDev(UsbDevice device) {

            if (mCameraHelper == null || mCameraHelper.getUsbDeviceCount() == 0) {
                showShortMsg("check no usb camera");
                return;
            }
            // request open permission
            if (!isRequest) {
                isRequest = true;
                if (mCameraHelper != null) {
                    mCameraHelper.requestPermission(0);
                }
            }
        }

        @Override
        public void onDettachDev(UsbDevice device) {
            // close camera
            if (isRequest) {
                isRequest = false;
                mCameraHelper.closeCamera();
                showShortMsg(device.getDeviceName() + " is out");
            }
        }

        @Override
        public void onConnectDev(UsbDevice device, boolean isConnected) {
            if (!isConnected) {
                showShortMsg("fail to connect,please check resolution params");
                isPreview = false;
            } else {
                isPreview = true;
                showShortMsg("connecting");

                runOnUiThread(() -> {
                    pb.setVisibility(View.GONE);
                    countDisposable = Observable.interval(0,1,TimeUnit.SECONDS)
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(new Consumer<Long>() {
                                @Override
                                public void accept(Long aLong) throws Exception {
                                    int caclc = (int) (5 -aLong);
                                    btn_upload.setText(caclc + "");
                                    if (caclc == 0) {
                                        countDisposable.dispose();
                                        btn_upload.setEnabled(true);
                                        btn_upload.setText("前七后八");
                                    }
                                }
                            });
                    record();
                });
            }
        }

        @Override
        public void onDisConnectDev(UsbDevice device) {
            showShortMsg("disconnecting");
            if (recordDisposable != null) {
                recordDisposable.dispose();
            }
            CollectUtil.getInstance().close();
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_usbcamera);
        initView();

        // step.1 initialize UVCCameraHelper
        mUVCCameraView = (CameraViewInterface) mTextureView;
        mUVCCameraView.setCallback(this);
        mCameraHelper = UVCCameraHelper.getInstance();
        mCameraHelper.setDefaultFrameFormat(UVCCamera.PIXEL_FORMAT_YUV420SP);
        mCameraHelper.initUSBMonitor(this, mUVCCameraView, listener);
        mCameraHelper.setOnPreviewFrameListener(new AbstractUVCCameraHandler.OnPreViewResultListener() {
            @Override
            public void onPreviewResult(byte[] nv21Yuv) {
                CollectUtil.getInstance().writeVideoData(nv21Yuv);
            }
        });
        Req.Companion.getRetrofit().create(Other.class)
                .checkVersion("android")
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new Consumer<AppVersion>() {
                    @Override
                    public void accept(AppVersion appVersion) throws Exception {
                        if (appVersion != null && appVersion.getCode() == 0) {
                            AppVersion.Info info = appVersion.getAppVersion();
                            if (info == null) {
                                return;
                            }
                            int localCode = SysUtil.getVersionCode(USBCameraActivity.this);
                            if (localCode != info.getVersion()) {
                                //更新
                                if ("Y".equals(info.getUpdateFlag())) {
                                    downApp(info.getUrl());
                                } else {
                                    new AlertDialog.Builder(USBCameraActivity.this)
                                            .setMessage(info.getTitle())
                                            .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                                                @Override
                                                public void onClick(DialogInterface dialogInterface, int i) {
                                                    downApp(info.getUrl());
                                                }
                                            }).setNegativeButton("取消",null).show();
                                }
                            }
                        }
                    }
                });
        online();
    }

    private void online() {
        onlineDisposable = Observable.interval(15,TimeUnit.SECONDS)
                .subscribeOn(Schedulers.single())
                .observeOn(Schedulers.single())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Req.Companion.getRetrofit().create(Other.class)
                                .online(SPUtil.getPlateNumber(App.context))
                                .subscribe();
                    }
                });
    }

    private void downApp(String url) {
        FileUtil.download(url, new File(FileUtil.createFile("app.apk")), new DownloadListener4() {
            @Override
            public void taskStart(@NonNull DownloadTask task) {
                fl_down.setVisibility(View.VISIBLE);
            }

            @Override
            public void connectStart(@NonNull DownloadTask task, int blockIndex, @NonNull Map<String, List<String>> requestHeaderFields) {

            }

            @Override
            public void connectEnd(@NonNull DownloadTask task, int blockIndex, int responseCode, @NonNull Map<String, List<String>> responseHeaderFields) {

            }

            @Override
            public void infoReady(DownloadTask task, @NonNull BreakpointInfo info, boolean fromBreakpoint, @NonNull Listener4Assist.Listener4Model model) {
                //文件总大小
            }

            @Override
            public void progressBlock(DownloadTask task, int blockIndex, long currentBlockOffset) {

            }

            @Override
            public void progress(DownloadTask task, long currentOffset) {

            }

            @Override
            public void blockEnd(DownloadTask task, int blockIndex, BlockInfo info) {

            }

            @Override
            public void taskEnd(DownloadTask task, EndCause cause, @Nullable Exception realCause, @NonNull Listener4Assist.Listener4Model model) {
                fl_down.setVisibility(View.GONE);
                if (cause == EndCause.COMPLETED) {
                    SysUtil.install(USBCameraActivity.this,task.getFile());
                } else {
                    Toast.makeText(USBCameraActivity.this,"载失败，请检查网络",Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (TextUtils.isEmpty(SPUtil.getPlateNumber(this))) {
            PlateNumberActivity.launcher(this);
        }
    }

    private void initView() {
        fl_down = (FrameLayout) findViewById(R.id.fl_down);
        mTextureView = findViewById(R.id.camera_view);
        pb = (ProgressBar) findViewById(R.id.pb);
        btn_upload = (Button) findViewById(R.id.btn_upload);
        btn_upload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                if (!isPreview) {
//                    Toast.makeText(USBCameraActivity.this,"还没有开始录制",Toast.LENGTH_SHORT).show();
//                    return;
//                }
                if (Mp4Util.getInstance().isUploading) {
                    Toast.makeText(USBCameraActivity.this,"前七后八进行中",Toast.LENGTH_SHORT).show();
                    return;
                }
                Mp4Util.getInstance().start();
            }
        });
    }

    private void record() {
        if (recordDisposable != null) {
            recordDisposable.dispose();
        }
        //每隔60秒进行一次mp4合成
        recordDisposable = Observable.interval(0,Constant.DRUATION,TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        CollectUtil.getInstance().start(Mp4Util.getInstance().currFileName = String.valueOf(System.nanoTime()),UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT);
                    }
                });
    }

    @Override
    protected void onStart() {
        super.onStart();
        // step.2 register USB event broadcast
        if (mCameraHelper != null) {
            mCameraHelper.registerUSB();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        // step.3 unregister USB event broadcast
        if (mCameraHelper != null) {
            mCameraHelper.unregisterUSB();
        }
        if (recordDisposable != null) {
            recordDisposable.dispose();
        }
        CollectUtil.getInstance().close();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        FileUtils.releaseFile();
        // step.4 release uvc camera resources
        if (mCameraHelper != null) {
            mCameraHelper.release();
        }
        if (onlineDisposable != null) {
            onlineDisposable.dispose();
        }
    }

    // example: {640x480,320x240,etc}
    private List<String> getResolutionList() {
        List<Size> list = mCameraHelper.getSupportedPreviewSizes();
        List<String> resolutions = null;
        if (list != null && list.size() != 0) {
            resolutions = new ArrayList<>();
            for (Size size : list) {
                if (size != null) {
                    resolutions.add(size.width + "x" + size.height);
                }
            }
        }
        return resolutions;
    }

    private void showShortMsg(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public USBMonitor getUSBMonitor() {
        return mCameraHelper.getUSBMonitor();
    }

    @Override
    public void onDialogResult(boolean canceled) {
        if (canceled) {
            showShortMsg("取消操作");
        }
    }

    @Override
    public void onSurfaceCreated(CameraViewInterface view, Surface surface) {
        if (!isPreview && mCameraHelper.isCameraOpened()) {
            mCameraHelper.startPreview(mUVCCameraView);
            isPreview = true;
        }
    }

    @Override
    public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) {

    }

    @Override
    public void onSurfaceDestroy(CameraViewInterface view, Surface surface) {
        if (isPreview && mCameraHelper.isCameraOpened()) {
            mCameraHelper.stopPreview();
            isPreview = false;
        }
    }
}
